package com.cgs.query.monitor.metrics

import com.cgs.query.util.Utils
import io.micrometer.core.instrument.Meter
import io.micrometer.core.instrument.Tag
import io.micrometer.core.instrument.Timer
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig
import io.micrometer.core.instrument.distribution.pause.PauseDetector
import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import java.util.concurrent.Callable
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong

class QueryMeterRegistry : SimpleMeterRegistry() {

    override fun newTimer(id: Meter.Id, distributionStatisticConfig: DistributionStatisticConfig, pauseDetector: PauseDetector): Timer {
        return TimerWrapper(super.newTimer(id, distributionStatisticConfig, pauseDetector))
    }

    override fun timer(name: String, tags: MutableIterable<Tag>): Timer {
        return TimerWrapper(super.timer(name, tags))
    }

    override fun timer(name: String, vararg tags: String?): Timer {
        return TimerWrapper(super.timer(name, *tags))
    }

    class TimerWrapper(val timer: Timer) : Timer by timer {

        val fCount = AtomicLong(0)
        var lastTime: Long = System.currentTimeMillis()

        override fun <T : Any?> recordCallable(f: Callable<T>): T {
            return timer.recordCallable(f).apply {
                lastTime = System.currentTimeMillis()
            }
        }

        fun toProjectTimerInfo(): ProjectTimerInfo? {
            return Utils.notNullAndConsume(id.getTag("callName")) {
                ProjectTimerInfo(it, lastTime, count(), fCount.get(),
                        "${mean(TimeUnit.MILLISECONDS).toInt()} ms",
                        "${max(TimeUnit.MILLISECONDS).toInt()} ms")
            }
        }
    }
}